using System;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using System.Data;
using System.Linq;
using Baik.Interface.Execution;
using Baik.Interface.Expression;
using Baik.Interface.Framework;
using IUndefined = Baik.Interface.Execution.IUndefined;

namespace Baik.Expression
{
    public class ArrayLiteral : Expression, IArrayLiteral
    {
        public ArrayLiteral(IInjector inject) : base(inject)
        {
        }

        public override IObject Evaluate()
        {
            var rtn = Inject.Instantiate<IArray>();
            rtn.Items = Expressions.Select(e => e.Evaluate()).ToList();
            return rtn;
        }

        private string partstring()
        {
            var lst = Expressions as IExpression[] ?? Expressions.ToArray();
            var sw = new System.IO.StringWriter();
            for (int i = 0; i < lst.Length; i++)
            {
                if (i > 0){sw.Write(", ");}
                sw.Write(lst[i].AsString());
            }
            return sw.ToString();
        }
        public string AsString()
        {
            return "[" + partstring() + "]";
        }
        public IEnumerable<IExpression> Expressions { get; set; }
    }

    public class ArrayReference : Expression, IArrayReference
    {
        public IExceptionThrower Thrower { get; private set; }
        public ArrayReference(IInjector inject, IExceptionThrower thrower) : base(inject)
        {
            Thrower = thrower;
        }

        public override IObject Evaluate()
        {
            var arr = Reference.Evaluate(EvaluationScope);
            var idx = Index.Evaluate(EvaluationScope);
            if (arr is IArray && idx is INumber)
            {
                return (arr as IArray).GetByIndex(((INumber) idx).Value);
            }
            else if (idx is IString)
            {
                return arr.Get(((IString) idx).Value);
            }
            else
            {
                Thrower.Throw("You can only use array referencing with numbers for arrays and strings for objects");
                return Inject.Instantiate<IUndefined>();
            }

        }



        public IExpression Reference { get; set; }
        public IExpression Index { get; set; }
    }
}